/*****************************************************************************
*
*  PROJECT:     Multi Theft Auto v1.2
*  LICENSE:     See LICENSE in the top level directory
*  FILE:        FileSystem/src/fsinternal/CFileSystem.platformutils.hxx
*  PURPOSE:     FileSystem platform dependant utilities
*
*  Multi Theft Auto is available from http://www.multitheftauto.com/
*
*****************************************************************************/

#ifndef _FILESYSTEM_PLATFORM_UTILITIES_
#define _FILESYSTEM_PLATFORM_UTILITIES_

#include "CFileSystem.translator.system.h"

// Make sure you included platform header!

// Function for creating an OS native directory.
inline bool _File_CreateDirectory( const filePath& thePath )
{
#ifdef __linux__
    if ( mkdir( osPath, FILE_ACCESS_FLAG ) == 0 )
        return true;

    switch( errno )
    {
    case EEXIST:
    case 0:
        return true;
    }

    return false;
#elif defined(_WIN32)
    // Make sure a file with that name does not exist.
    DWORD attrib = INVALID_FILE_ATTRIBUTES;

    filePath pathToMaybeFile = thePath;
    pathToMaybeFile.resize( pathToMaybeFile.size() - 1 );

    if ( const char *ansiPath = pathToMaybeFile.c_str() )
    {
        attrib = GetFileAttributesA( ansiPath );
    }
    else if ( const wchar_t *widePath = pathToMaybeFile.w_str() )
    {
        attrib = GetFileAttributesW( widePath );
    }

    if ( attrib != INVALID_FILE_ATTRIBUTES )
    {
        if ( !( attrib & FILE_ATTRIBUTE_DIRECTORY ) )
            return false;
    }

    BOOL dirSuccess = FALSE;

    if ( const char *ansiPath = thePath.c_str() )
    {
        dirSuccess = CreateDirectoryA( ansiPath, NULL );
    }
    else if ( const wchar_t *widePath = thePath.w_str() )
    {
        dirSuccess = CreateDirectoryW( widePath, NULL );
    }

    return ( dirSuccess == TRUE || GetLastError() == ERROR_ALREADY_EXISTS );
#else
    return false;
#endif //OS DEPENDANT CODE
}

template <typename charType>
AINLINE void _FileWin32_PathRootDispatch( const charType *path, eRootPathType& pathType, filePath& uncPart )
{
    // Parses a fully qualified path into a thing we can understand.

    if ( _File_IsAbsolutePath( path ) )
    {
        pathType = eRootPathType::DISK;
        return;
    }
    else
    {
        const charType *uncEnd;

        if ( _File_IsUNCPath( path, uncEnd, uncPart ) )
        {
            pathType = eRootPathType::UNC;
            return;
        }
    }
    
    // No idea.
    pathType = eRootPathType::UNKNOWN;
}

template <typename charType, typename processorType>
AINLINE bool _FileWin32_PathRootDetect( const charType *path, processorType& cb, bool& success )
{
    if ( _File_IsAbsolutePath( path ) )
    {
        if ( cb.getRootPathType() != eRootPathType::DISK || cb.doesDriveLetterMatch( path[0] ) == false )
        {
            success = false;   // drive mismatch
        }
        else
        {
            success = cb.onAbsolutePath( path + 3 );
        }

        return true;
    }
    else
    {
        filePath uncPart;
        const charType *uncEnd;

        if ( _File_IsUNCPath( path, uncEnd, uncPart ) )
        {
            // Make sure UNC descriptors match.
            if ( cb.getRootPathType() != eRootPathType::UNC || cb.doesUNCDescMatch( uncPart ) == false )
            {
                success = false;    // wrong UNC.
            }
            else
            {
                success = cb.onAbsolutePath( uncEnd );
            }

            return true;
        }
    }

    return false;
}

// Common purpose powerful helper for root comparison of fully qualified paths.
// Implementations can use the function above for cached functionality!
template <typename charType>
inline bool _FileWin32_ComparePathRoot( const charType *primPath, const charType *secPath )
{
    struct _win32GenericRootPathProc
    {
        AINLINE _win32GenericRootPathProc( const charType *primPath )
        {
            _FileWin32_PathRootDispatch( primPath, pathType, unc );

            this->fullPath = primPath;
        }

        AINLINE eRootPathType getRootPathType( void ) const
        {
            return this->pathType;
        }

        AINLINE bool doesDriveLetterMatch( charType driveLetter ) const
        {
            return ( UniversalCompareStrings( fullPath, 1, &driveLetter, 1, false ) );
        }

        AINLINE bool doesUNCDescMatch( const filePath& uncDesc ) const
        {
            return ( this->unc.equals( uncDesc, false ) );
        }

        AINLINE bool onAbsolutePath( const charType *path ) const
        {
            return true;
        }

    private:
        const charType *fullPath;

        eRootPathType pathType;
        filePath unc;
    };

    _win32GenericRootPathProc nativePathProc( primPath );

    bool success;

    if ( _FileWin32_PathRootDetect( secPath, nativePathProc, success ) )
    {
        return success;
    }

    return false;
}

#endif //_FILESYSTEM_PLATFORM_UTILITIES_